package test.myorm.executor;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.collections4.CollectionUtils;

import jodd.bean.BeanUtilBean;
import test.myorm.chain.Chain;
import test.myorm.chain.ProxyFactory;
import test.myorm.core.BaseMapping;
import test.myorm.core.Configuration;
import test.myorm.core.Parameter;
import test.myorm.core.ResultMap;
import test.myorm.core.Sql;
import test.myorm.handler.ResultSetHandler;
import test.myorm.handler.StatementHandler;

public class Executor {
	
	private DataSource dataSource;
	private StatementHandler statementHandler;
	private ResultSetHandler resultSetHandler;
	
	public Executor(Configuration configuration) {
		this.dataSource = configuration.getDataSource();
		Chain chain = new Chain();
		chain.addInterceptors(configuration.getInterceptors());
		System.out.println("interceptors=" + configuration.getInterceptors());
		ProxyFactory proxyFactory = new ProxyFactory(chain);
		statementHandler = (StatementHandler) proxyFactory.getService(new StatementHandler()); 
		resultSetHandler = new ResultSetHandler(); 
	}
	
	public int update(Sql sql) throws SQLException {
		Connection connection = dataSource.getConnection();
		PreparedStatement ps = statementHandler.handle(sql, connection);
		ps.executeUpdate();
		
		BeanUtilBean bub = new BeanUtilBean();
		Object[] params = sql.getParameter().getOrgParam();
		if(params!=null && params.length==1) {
			int returnIdType = sql.getReturnIdType();
			Object param = params[0];
			if(returnIdType==Sql.ID_GENERATE) {
				ResultSet rs = ps.getGeneratedKeys();
				if(rs.next()) {
					Object id = rs.getObject(1);
					bub.setProperty(param, sql.getIdProperty(), id);
				}
			} else if(returnIdType==Sql.ID_SELECT) {
				Sql idSql = new Sql();
				idSql.setSql(sql.getIdSql());
				idSql.setParameter(new Parameter());
				idSql.setType(Sql.SQL_SELECT);
				Class idPropertyClass = bub.getPropertyType(param, sql.getIdProperty());
				idSql.setResultMap(new ResultMap(BaseMapping.getShortResultType(idPropertyClass.getSimpleName())));
				System.out.println(idSql);
				Object id = selectOne(idSql, connection);
				bub.setProperty(param, sql.getIdProperty(), id);
				System.out.println(id);
			}
			
		}
		
		return ps.getUpdateCount();
	}
	
	public <T> List<T> selectList(Sql sql, Connection connection) throws SQLException {
		PreparedStatement ps = statementHandler.handle(sql, connection);
		ResultSet rs = ps.executeQuery();
		List<T> list = resultSetHandler.handle(sql, rs);
		return list;
	}
	
	public <T> List<T> selectList(Sql sql) throws SQLException {
		return selectList(sql, dataSource.getConnection());
	}
	
	public Object selectOne(Sql sql, Connection connection) throws SQLException {
		PreparedStatement ps = statementHandler.handle(sql, connection);
		ResultSet rs = ps.executeQuery();
		List list = resultSetHandler.handle(sql, rs);
		if(CollectionUtils.isEmpty(list)) {
			return null;
		} else if(list.size() > 1) {
			throw new RuntimeException("result size more than one!!");
		} else {
			return list.get(0);
		}
		
	}
	
	public Object selectOne(Sql sql) throws SQLException {
		return selectOne(sql, dataSource.getConnection());
	}

}
